#include <iostream>
#include "../include/dbserverapp.h"
#include "../../util/cpp/util/gwmd5.h"
#include "../../util/cpp/util/gwcommon.h"
#include "../include/dbmsgprocdispatch.h"
#include "../include/mysqlquery.h"
#include "../include/dbtypes.h"
#include "messagetypes.h"

GW_IMPLEMENT_APPLICATION(DBServerApplication);

DBServerApplication::DBServerApplication():
m_bufferLength(0),
m_connHandle(INVALID_SESSION),
m_pMessageCache(0),
m_Port(0)
{
        this->SetApplicationName("DBServer");
        this->SetApplicationVersion("1.0.0.0");
        this->SetCompanyName("GrayWind");
}

/***************************************************************************************************************************/
DBServerApplication::~DBServerApplication()
{

}

/***************************************************************************************************************************/
void
DBServerApplication::OnMessage(int session_id, void* pMsgBuffer, unsigned long msgID, unsigned long msg_bytes, eOperateType type, int error_code)
{
        MsgProcDispatcher::dispatch(this, type, session_id, pMsgBuffer, msgID, msg_bytes, error_code);
}

/***************************************************************************************************************************/
void __stdcall NetworkInvoke(int session_id, void* pMsgBuffer, unsigned long msgID, unsigned long msg_bytes, eOperateType type, int error_code)
{
        ((DBServerApplication*)DBServerApplication::GetApp())->OnMessage(session_id, pMsgBuffer, msgID, msg_bytes, type, error_code);
}

/***************************************************************************************************************************/
bool
DBServerApplication::Open()
{
        gwApplication::Open();

        do
        {
                std::cout<<"Application Name:"<<GetApplicationName()<<std::endl;
                std::cout<<"Application Version:"<<GetApplicationVersion()<<std::endl;
                std::cout<<"Application Version MD5:"<<gwBedrockUtil::gwMD5Transformer::generate(GetApplicationVersion())<<std::endl;
                std::cout<<"Company Name:"<<GetCompanyName()<<std::endl;

                std::cout<<"Options:"<<std::endl;
                std::cout<<"        -i(IP. defualt 127.0.0.1)"<<std::endl;
                std::cout<<"        -p(Port. defualt 3370)"<<std::endl;
                std::cout<<"        -l(MaxListen. default 1)"<<std::endl;
                std::cout<<"        -t(I/O ThreadsNum. default 1)"<<std::endl;
                std::cout<<"        -b(Buffer Length(kb). defualt 64)"<<std::endl;
                std::cout<<"        -g(GatewayIP. default local)"<<std::endl;
                std::cout<<"        -gp(GatewayPort. defualt 2233)"<<std::endl;
                std::cout<<"        -m(MysqlServerIP. default local)"<<std::endl;
                std::cout<<"        -mp(MysqlServerPort. default 3306)"<<std::endl;
                std::cout<<"        -mu(MysqlServerUsrName. default root)"<<std::endl;
                std::cout<<"        -mk(MysqlServerPassword. default root)"<<std::endl;

                create_service();
                std::cout<<"Create Network Service Completely!"<<std::endl;

                ///get server arguments
		        m_strIP                   = m_commandLineArgs.GetString("i", "127.0.0.1");
                m_Port                    = m_commandLineArgs.GetInt("p", 3370);
                int         nListen       = m_commandLineArgs.GetInt("l", 1);
                int         nConn         = 1;
                int         nIoThreadNum  = m_commandLineArgs.GetInt("t", 1);
                ///numbers in kilobyte
                m_bufferLength            = m_commandLineArgs.GetInt("b", 64);
		        m_bufferLength *= 1024;

                ///gateway server info
                m_strGatewayIP             = m_commandLineArgs.GetString("g", "127.0.0.1");
                m_GatewayPort              = m_commandLineArgs.GetInt("gp", 3375);
                ///mysql server info
                std::string strMysqlIP     = m_commandLineArgs.GetString("m", "127.0.0.1");
                int         nMysqlPort     = m_commandLineArgs.GetInt("mp", 3306);
                std::string strMysqlUsr    = m_commandLineArgs.GetString("mu", "root");
                std::string strMysqlPsw    = m_commandLineArgs.GetString("mk", "root");
                std::cout<<"Parse Arguments Completely!"<<std::endl;

                std::cout<<"Initialize Network Service With:"<<std::endl;
                std::cout<<"Max Listen:"<<nListen<<std::endl;
                std::cout<<"Max Connect:"<<nConn<<std::endl;
                std::cout<<"Threads Number Of I/O Service:"<<nIoThreadNum<<std::endl;
                std::cout<<"Bytes Length Per Buffer:"<<m_bufferLength<<std::endl;

                initialize_service(nIoThreadNum, nListen + nConn, m_bufferLength);

		        m_pMessageCache = gw_new(MessageCache(m_bufferLength, 100));

		        if(m_pMessageCache == 0)
		                break;

                if(is_service_init() == false)
                        break;

                std::cout<<"Initialize Network Service Completely!"<<std::endl;

                start_service();
                std::cout<<"Start Network Service!"<<std::endl;

                if(start_listen(m_Port, NetworkInvoke) == false)
                        break;
                std::cout<<"Listen On Port:"<<m_Port<<std::endl;

                m_connHandle = start_connect(m_strGatewayIP.c_str(), m_GatewayPort, NetworkInvoke);
                if(m_connHandle == INVALID_SESSION)
                        break;
                std::cout<<"Connect To Gateway Server:"<<m_strGatewayIP<<":"<<m_GatewayPort<<std::endl;

		        MysqlService::Create();

		        std::cout<<"Connect To Mysql Server:"<<strMysqlIP<<":"<<nMysqlPort<<std::endl;
                MysqlService::Instance()->OpenConnection(AccountDB, strMysqlIP, nMysqlPort, "projnano", strMysqlUsr, strMysqlPsw);
                if(MysqlService::Instance()->IsConnectionOpen(AccountDB) == false)
			            break;

		        std::cout<<"Connect To Mysql Server Success!"<<std::endl;

                        return true;
        }
        while(0);

	    std::cout<<"Open Database Server Error!"<<std::endl;
        return false;
}

/***************************************************************************************************************************/
void
DBServerApplication::Close()
{
    close_session(m_connHandle);
    m_connHandle = INVALID_SESSION;
    close_listen();
    terminate_service();
    destroy_service();
    gw_delete(m_pMessageCache);

    gwApplication::Close();
}

/***************************************************************************************************************************/
void
DBServerApplication::SendNotify(int session_id)
{
    msgGBServer_Notify msg(session_id, ServerType_DBServer);
    gwMessagePort::ProcessMessage(&msg);
}

/***************************************************************************************************************************/
void
DBServerApplication::StoreMessage(int session_id, void* pMsgBuffer, unsigned long msgID, unsigned long msg_bytes)
{
	gwAssert(m_pMessageCache != 0);
	m_pMessageCache->write(session_id, msgID, msg_bytes, pMsgBuffer);
}

/***************************************************************************************************************************/
void
DBServerApplication::RegisterServer(int session_id)
{
    msgGWServer_Register msg(session_id, m_strIP, m_Port, ServerType_DBServer);
    gwMessagePort::ProcessMessage(&msg);
}

/***************************************************************************************************************************/
void
DBServerApplication::ProcessMessage()
{
	gwAssert(m_pMessageCache != 0);
	static stMessageCacheUnit unit(m_bufferLength);
	m_pMessageCache->read(unit);

	if(unit.SessionId != -1)
	{
        NetMessageProcessor::ProcessMessage(this, unit.SessionId, unit.Buffer, unit.MsgId, unit.MsgBytes);
	    unit.discard();
	}
}

/***************************************************************************************************************************/
void
DBServerApplication::Run()
{
	ProcessMessage();
}
